#ifndef __NURBS_SURFACE_RENDERER_NURBS__
#define __NURBS_SURFACE_RENDERER_NURBS__

#include "primitiverenderer.h"
#include "nurbssurfacemesh.h"

class NurbsSurfaceRenderer : public PrimitiveRenderer {
 public:
	NurbsSurfaceRenderer(NurbsSurfaceMesh* primitive);
	virtual void Init();
	virtual void Render() const;
	virtual void Update();
	virtual ~NurbsSurfaceRenderer();
 private:
	std::vector<Array2V3n> position;
	std::vector<Array2V3n> normal;
	std::vector<Array2> parameterU, parameterV;
	
	std::vector<SNurbs*> element;

	std::string positionAttribute;

	void Tesselate(const std::string& attributeU, const std::string& attributeV);
	void RenderFilledElement(size_t k) const;
	void RenderBoundaryElement(size_t k) const;
	void RenderGeometry() const;
};

template<typename T>
void Tesselate(SNurbs* element, const std::string& attribute, boost::multi_array<T, 2>& data) {
	const std::pair<Vec2n, Vec2n>& domain = element->Domain();
	const Vec2n& uDomain = domain.first;
	const Vec2n& vDomain = domain.second;

	const size_t n = data.shape()[0];
	const size_t m = data.shape()[1];

	const nfloat eps0 = 0.0;
	const nfloat eps1 = 1.0;

	for(size_t i = 0; i < n; i++) {
		nfloat u = eps1 * ((nfloat)i / (n - 1));
		u = u * (uDomain[1] - uDomain[0]) + uDomain[0];
		if(i == 0) u = uDomain[0] + eps0;
		for(size_t j = 0; j < m; j++) {							
			nfloat v = eps1 * ((nfloat)j / (m - 1));
			v = v * (vDomain[1] - vDomain[0]) + vDomain[0];
			if(j == 0) v = vDomain[0] + eps0;

			data[i][j] = element->Evaluate<T>(math::V2n(u, v), attribute);
		}
	}
}

#endif //__NURBS_SURFACE_RENDERER_NURBS__
